import { reactive } from 'vue'

export type AsyncState<T> =
  | {
      loading: boolean
      error?: undefined
      result?: undefined
    }
  | {
      loading: false
      error: Error
      result?: undefined
    }
  | {
      loading: false
      error?: undefined
      result?: T
    }

export type AsyncFn<Vue = any, Args extends any[] = any[]> = [
  AsyncState<Vue>,
  (...args: Args) => Promise<Vue | null>,
]

export default function useAsyncFn<Vue = any, Args extends any[] = any[]>(
  fn: (...args: Args) => Promise<Vue>,
): AsyncFn<Vue, Args> {
  const state: AsyncState<Vue> = reactive({
    loading: false,
  })
  const callback = async (...args: Args) => {
    state.loading = true
    try {
      const data = await fn(...args)
      state.result = data
      state.loading = false
      return data
    } catch (error) {
      state.error = error
      state.loading = false
      return null
    }
  }
  return [state, callback]
}
